﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ImryStefanGAnamespace
{
    public class Segment
    {
        public double segmentDemand { get; private set; }

        public int numberOfNodesVisited { get; private set; }

        public List<int> nodesOnSegment;
                
        public Segment()
        {
            nodesOnSegment = new List<int>();
        }

        public Segment(int i)
        {
            nodesOnSegment = new List<int>();
            Add(0);
            Add(i);
            Add(0);
            numberOfNodesVisited = 1;
        }

        public void Add(int item)
        {
            nodesOnSegment.Add(item);
            if (item > 0)
            {
                segmentDemand += Program.vrpData.Demands[item];
                numberOfNodesVisited++;
            }
        }

        internal void AddRange(Segment segment)
        {
            if (this.nodesOnSegment.Last() == 0)
                this.RemoveLastNode();

            if (segment.nodesOnSegment.First() == 0)
                segment.RemoveNodesUpToAndIncluding(0);

            for (int i = 0; i < segment.nodesOnSegment.Count(); i++)
                if (segment.nodesOnSegment[i] > 0) numberOfNodesVisited++;

            nodesOnSegment.AddRange(segment.nodesOnSegment);
            this.segmentDemand += segment.segmentDemand;
        }

        internal void Insert(int mergeAt, int nodeIndex)
        {
            nodesOnSegment.Insert(mergeAt, nodeIndex);
            if (nodeIndex > 0)
            {
                this.segmentDemand += Program.vrpData.Demands[nodeIndex];
                numberOfNodesVisited++;
            }
        }

        internal void InsertRange(int mergeAt, Segment segment)
        {
            for (int i = 0; i < segment.nodesOnSegment.Count(); i++)
                if (segment.nodesOnSegment[i] > 0) numberOfNodesVisited++;
            nodesOnSegment.InsertRange(mergeAt, segment.nodesOnSegment);
            this.segmentDemand += segment.segmentDemand;
        }
        
        internal void RemoveNodesUpToAndIncluding(int splittingAfterIndex)
        {
            for (int j = 0; j <= splittingAfterIndex; j++)
            {
                if (nodesOnSegment.First() > 0)
                {
                    segmentDemand -= Program.vrpData.Demands[nodesOnSegment.First()];
                    numberOfNodesVisited--;
                }
                nodesOnSegment.RemoveAt(0);
            }
        }

        internal void RemoveLastNode()
        {
            if (nodesOnSegment.Last() > 0)
            {
                segmentDemand -= Program.vrpData.Demands[nodesOnSegment.Last()];
                numberOfNodesVisited--;
            }
            nodesOnSegment.RemoveAt(nodesOnSegment.Count() - 1);
        }
        
        internal Segment Clone()
        {
            Segment theClone = new Segment();
            for (int i = 0; i < nodesOnSegment.Count(); i++)
                theClone.nodesOnSegment.Add(nodesOnSegment[i]);
            theClone.segmentDemand = segmentDemand;
            theClone.numberOfNodesVisited = numberOfNodesVisited;
            return theClone;
        }

        internal double CalculateTotalCost()
        {
            double realTotalDistanceOnRoute = 0;
            for (int i = 0; i < nodesOnSegment.Count() -1; i++)
                realTotalDistanceOnRoute += Program.vrpData.Distances[nodesOnSegment[i], nodesOnSegment[i + 1]];
            return realTotalDistanceOnRoute;
        }

        internal void Replace(int iNode, int j)
        {
            this.segmentDemand -= Program.vrpData.Demands[nodesOnSegment[iNode]];
            nodesOnSegment[iNode] = j;
            this.segmentDemand += Program.vrpData.Demands[j];
        }

        // Remove -1's and add 0's if needed
        internal void Cleanup()
        {
            if(nodesOnSegment[0]!=0)
                nodesOnSegment.Insert(0, 0);
            if (nodesOnSegment.Last() != 0)
                nodesOnSegment.Add(0);
            for (int i = 0; i < nodesOnSegment.Count(); i++)
            {
                if (nodesOnSegment[i] == -1)
                {
                    nodesOnSegment.RemoveAt(i);
                    i--;
                }
            }
        }
    }
}
